package com.mokylin.dbschema;

import com.mokylin.dbschema.dao.DbVersionDao;
import com.mokylin.dbschema.exception.DbVersionCheckUpdateException;
import com.mokylin.dbschema.exception.DbVersionExecuteException;
import com.mokylin.dbschema.exception.DbVersionIllegalStateException;
import com.mokylin.dbschema.handler.SqlVersionHandlerFactory;
import com.mokylin.dbschema.pojo.DbVersion;
import com.mokylin.dbschema.service.DbVersionHeartBeatService;
import com.mokylin.dbschema.service.DbVersionService;
import com.mokylin.dbschema.util.ClassInfoCache;
import com.mokylin.dbschema.config.ConfigInfo;
import com.mokylin.dbschema.util.DBUtils;
import com.mokylin.dbschema.util.GlobalUtils;
import com.mokylin.dbschema.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;

/**
 * dbschema主程序
 *
 * @author 李朝(Li.Zhao)
 * @since 2015/8/31.
 */

public class DbSchema {
    private static final Logger LOG = LoggerFactory.getLogger(DbSchema.class);

    private static DbVersionService dbVersionService = ClassInfoCache.getSingleton(DbVersionService.class);

    /**
     * @param configPrefix 配置的前缀，如：configPrefix="USER_",则读取相关配置时候会加上前缀，读取数据库地址DB_HOST的时候则读取的是"USER_DB_HOST";
     */
    public static void startup(String configPrefix) throws DbVersionExecuteException {
        ConfigInfo.setPREFIX(configPrefix);
        startup();
    }

    public static void startup() throws DbVersionExecuteException {
        //check and init configure
        validateConfig();
        initConfig();
        DbVersion dbVersion;
        try {

            try {
                DbVersionDao dbVersionDao = ClassInfoCache.getSingleton(DbVersionDao.class);
                dbVersionDao.modifyIncrementId(); // 修改主键为自增
            } catch (SQLException e) {
                LOG.error(e.getMessage(), e);
            }

            for (int i = 0; ; i++) {
                // check version table; init tables
                try {
                    dbVersion = dbVersionService.check();
                    LOG.info("current db version :{}", dbVersion.getVersion());
                    // get update sql files
                    boolean success = dbVersionService.buildSqlFilesAfter(dbVersion);
                    LOG.info("db schema execute result:{}", success);
                    // end version status;
                    dbVersionService.end();
                    break;
                } catch (DbVersionIllegalStateException e) {
                    LOG.info(e.getMessage() + ",retry");
                }
                if (i == ConfigInfo.getIllegalStateRetryNum()) {
                    throw new DbVersionExecuteException("retry max times:" + ConfigInfo.getIllegalStateRetryNum() + ",dbVersion");
                }
                try {
                    Thread.sleep(ConfigInfo.getDbConnectHeartbeatSeconds() * 1000);
                } catch (InterruptedException e) {
                    LOG.error(e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            dbVersionService.errorEnd(e.getMessage());
            if(e instanceof DbVersionExecuteException){
                throw (DbVersionExecuteException) e;
            }
            throw new DbVersionExecuteException(e.getMessage(), e);
        } finally {
            dbVersionService.dbLog();
            DbVersionHeartBeatService.shutdown();
            DBUtils.closeConnection();
        }
    }

    private static DbVersion endVersion;
    /**
     * 获取当前dbVersion信息
     * @return dbVersion信息
     */
    public static String showLog(){
        try {
            DbVersion dbVersion = null;
            if(endVersion!=null){
                dbVersion = endVersion;
            }else{
                dbVersion = dbVersionService.getDbVersion();
                if(DbVersion.Status.NORMAL.equals(dbVersion.getStatus()) || DbVersion.Status.ERROR.equals(dbVersion.getStatus())){
                    endVersion=dbVersion;
                }
            }
            return "current db version msg:"+dbVersion;
        } catch (SQLException e) {
            return "query db exeception:"+e.getMessage();
        }
    }

    private static void initConfig() {
        DBUtils.init();
        SqlVersionHandlerFactory.getSqlVersionHandler();
    }

    private static void validateConfig() {
        if (StringUtils.isBlank(ConfigInfo.getDbHost())) {
            throw new IllegalArgumentException("配置错误:数据库地址不能为空");
        }
        if (StringUtils.isBlank(ConfigInfo.getDbPort())) {
            throw new IllegalArgumentException("配置错误:数据库端口不能为空");
        }
        if (StringUtils.isBlank(ConfigInfo.getDbName())) {
            throw new IllegalArgumentException("配置错误:数据库名称不能为空");
        }
        if (StringUtils.isBlank(ConfigInfo.getDbUsername())) {
            throw new IllegalArgumentException("配置错误:数据库用户名不能为空");
        }
        if (StringUtils.isBlank(ConfigInfo.getJdbcDriver())) {
            throw new IllegalArgumentException("配置错误:数据库JDBC驱动不能为空");
        }
        if (StringUtils.isBlank(ConfigInfo.getSqlDir())) {
            throw new IllegalArgumentException("配置错误:数据库sql文件目录不能为空");
        }
        int port = Integer.parseInt(ConfigInfo.getDbPort());
        if (port < 0 || port > 65536) {
            throw new IllegalArgumentException();
        }
        //validate sql file exist?
    }

}